# -*- coding:utf8 -*-
import cgi
import httplib


HTTP_CODES = {k: '{} {}'.format(k, v.upper()) for k, v in httplib.responses.items()}


REQUEST_MAPS = {
    'GET': [],
    'POST': [],
    'PUT': [],
    'DELETE': [],
}


class BaseHttpException(Exception):
    status = 404


class NotFound(BaseHttpException):
    status = 404


class Request(object):
    GET = {}
    POST = {}
    PUT = {}
    DELETE = {}

    def __init__(self, environ):
        self._environ = environ

        self._path = self._environ.get('PATH_INFO', '/')
        self.method = self._environ.get('REQUEST_METHOD', 'GET').upper()
        self.query_string = self._environ.get('QUERY_STRING')
        self._get_params = {}
        self._post_params = {}
        self._params = {}
        content_length = self._environ.get('CONTENT_LENGTH', 0)
        self.content_length = int(content_length) if content_length else 0

    def get_post_body(self):
        if self.content_length != 0:
            raw_data = cgi.FieldStorage(fp=self._environ['wsgi.input'], environ=self._environ)
            post_params = {}
            for field in raw_data:
                if isinstance(raw_data[field], list):
                    post_params[field] = [_.value for _ in raw_data[field]]
                elif raw_data[field].filename:
                    post_params[field] = raw_data[field]
                else:
                    post_params[field] = raw_data[field].value
            return post_params
        return {}

    @property
    def path(self):
        if not self._path[-1] == '/':
            self._path = '{}/'.format(self._path)
        return self._path

    @property
    def get_params(self):
        if not self._get_params and self.query_string:
            self._get_params = dict([_.split('=') for _ in self.query_string.split('&')])
        return self._get_params

    @property
    def post_params(self):
        if not self._post_params:
            self._post_params = self.get_post_body()
        return self._post_params

    @property
    def params(self):
        if not self._params:
            self._params = dict(self.get_params)
            self._params.update(self.post_params)
        return self._params


def get_handler(request):
    if request.method not in REQUEST_MAPS:
        raise BaseHttpException('ayo, method {} not support. ganga!'.format(request.method))
    the_url_set, the_handler = None, None
    for url_set in REQUEST_MAPS[request.method]:
        if url_set[0] == request.path:
            the_handler = url_set[1]
            the_url_set = url_set
    if the_handler is not None:
        return [the_url_set, the_handler]
    raise NotFound('some unknown things happen. ganga!')


def handle_error(exception, environ, start_response):
    environ['wsgi.errors'].write("Exception occurred on '%s': %s\n" % (environ['PATH_INFO'], exception[0]))
    start_response(HTTP_CODES[404], [('Content-Type', 'text/plain')])
    return [HTTP_CODES[404]]


def request_handler(environ, start_response):
    request = Request(environ)
    try:
        url_set, handle = get_handler(request)
        response = handle(request)
    except Exception as e:
        return handle_error(e, environ, start_response)
    start_response(HTTP_CODES.get(200), [('Content-Type', 'text/html')])
    return response


def run_server(host='localhost', port=8080):
    try:
        print 'start up...'
        from wsgiref.simple_server import make_server
        server = make_server(host=host, port=port, app=request_handler)
        server.serve_forever()
    except KeyboardInterrupt:
        print 'shutting down'
        import sys
        sys.exit()


def rough_route(path, method='get'):
    """
    :param path:
    :type path: str
    :param method:
    :type method: str
    :return:
    """
    def wrapper(func):
        def _wrapper(*args, **kwargs):
            return func(*args, **kwargs)
        up_method = method.upper()
        REQUEST_MAPS[up_method].append((path, _wrapper))
        return _wrapper
    return wrapper


if __name__ == "__main__":
    run_server()
